package com.marketlive.app.b2c.struts.security;

/*
(C) Copyright MarketLive. 2006. All rights reserved.
MarketLive is a trademark of MarketLive, Inc.
Warning: This computer program is protected by copyright law and international treaties.
Unauthorized reproduction or distribution of this program, or any portion of it, may result
in severe civil and criminal penalties, and will be prosecuted to the maximum extent
possible under the law.
*/

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.marketlive.system.config.IConfigurationManager;

import javax.servlet.http.*;
import javax.servlet.*;
import java.util.*;
import java.net.URI;
import java.net.URLEncoder;

import com.marketlive.app.b2c.WebUtil;

/**
 * Created by IntelliJ IDEA.
 * User: PeterS
 * Date: Jan 19, 2006
 * Time: 11:19:26 AM
 * To change this template use File | Settings | File Templates.
 * Utility for working with SSL requests.
 * taken from: http://www.javaworld.com/javaworld/jw-02-2002/jw-0215-ssl-p3.html
 */
public class SSLUtility {
    private static Log log = LogFactory.getLog(SSLUtility.class);

    private static final String HTTP = "http";
    private static final String HTTPS = "https";
    public static final String HTTP_PORT_PARAM = "listenPort_http";
    public static final String HTTPS_PORT_PARAM = "listenPort_https";
    private static String HTTP_PORT = null;
    private static String HTTPS_PORT = null;
    private static String standardHTTPPort;
    private static String standardHTTPSPort;
    private static final String PORT_80 = "80";
    private static final String PORT_443 = "443";
    private static final String STOWED_REQUEST_ATTRIBS = "ssl.redirect.attrib.stowed";

    static public String getRedirectString(HttpServletRequest request,
                                           ServletContext servletContext,
                                           boolean isSecure) {

        IConfigurationManager configurationManager = WebUtil.getConfigurationManager(request);
        standardHTTPPort = configurationManager.getAsString("system.port.http");
        standardHTTPSPort = configurationManager.getAsString("system.port.https");

        initializeSchemePorts(servletContext);

        // get the scheme we want to use for this page and
        // get the scheme used in this request
        String desiredProtocol = isSecure ? HTTPS : HTTP;
        String usingProtocol = request.getScheme();

        // Determine the port number we want to use
        // and the port number we used in this request
        String desiredPort = isSecure ? HTTPS_PORT : HTTP_PORT;
        String usingPort = String.valueOf(request.getServerPort());

        // if the goSecure property is not set=true in the context.properties file, get out without changing anything
        boolean goSecure = configurationManager.isGoSecure();
        if (!goSecure){
            return null;
        }

        String urlString = null;

        // Must also check ports, because of IE multiple redirect problem
        if (!desiredProtocol.equals(usingProtocol) || !desiredPort.equals(usingPort)) {

        	// rebuild the URL using the desired protocol/port
        	urlString = buildNewUrlString(request.getRequestURL().toString(), 
        			                      request.getQueryString(), 
        			                      request.getParameterMap(), 
        			                      desiredProtocol,
        			                      desiredPort);

        	// Temporarily store attributes in session
        	stowRequestAttributes(request);
        } else {
        	// Retrieve attributes from session
        	reclaimRequestAttributes(request);
        }

        return urlString;

    }

    /**
     * Initializes the port numbers based on the port init parameters as defined
     * in web.xml
     */
    private static void initializeSchemePorts(ServletContext servletContext) {

        if (HTTP_PORT == null) {
            String portNumber = servletContext.getInitParameter(HTTP_PORT_PARAM);
            HTTP_PORT = (portNumber == null ? standardHTTPPort : portNumber);
        }
        if (HTTPS_PORT == null) {
            String portNumber = servletContext.getInitParameter(HTTPS_PORT_PARAM);
            HTTPS_PORT = (portNumber == null ? standardHTTPSPort : portNumber);
        }
    }

    /**
     * Builds the URL that we will redirect to with desired protocol and port
     */
    public static String buildNewUrlString(String requestURL, String queryString, Map paramMap, String desiredProtocol, String desiredPort) {
    	
    	StringBuffer url = null;
    	URI outputURI;
		try {
			URI inputURI = new URI(requestURL);
			int port = ((desiredPort.equals(PORT_80)) || (desiredPort.equals(PORT_443))) ? -1 : Integer.parseInt(desiredPort);
			outputURI = new URI(desiredProtocol, inputURI.getUserInfo(), inputURI.getHost(), 
					            port, inputURI.getPath(), inputURI.getQuery(), inputURI.getFragment());
		} catch (Exception e) {
			log.error("Exception occurred attempting to build URL:", e);
			return requestURL;
		} 
    	
        url = new StringBuffer(outputURI.toString());
        
        return appendQueryStringParameters(url, queryString, paramMap);

    }
    
    /**
     * Append query-string, or parameters as query-string, to the url from request body parameters
     */
    private static String appendQueryStringParameters(StringBuffer urlSB, String queryString, Map paramMap) {

    	StringBuffer appendParam = new StringBuffer("");

    	// add query string, if any
    	if (queryString != null && queryString.length() != 0) {
    		appendParam.append("?" + queryString);
    	} else {
    		Set keyNameSet = paramMap.keySet();
    		if ((keyNameSet != null) && (!keyNameSet.isEmpty())){
    			Iterator names = paramMap.keySet().iterator();
    			try {
    				while (names.hasNext()) {
    					String name = (String) names.next();
    					String value = (String)paramMap.get(name);
    					String symbol = (appendParam.length() > 0) ? "&" : "?";
    					appendParam.append(symbol);
    					appendParam.append(URLEncoder.encode(name, "UTF-8"));
    					appendParam.append("=");
    					appendParam.append(URLEncoder.encode(value, "UTF-8"));
    				}
    			} catch (Exception e){
    				log.error("Exception occurred attempting to appendQueryString parameters:", e);
    			}
    		}
    	}
    	
    	// append if there is something to append 
    	if (appendParam.length() > 0){
    		urlSB.append(appendParam.toString());
    	}
    	
    	String urlString = urlSB.toString();
    	// if the url contains feature.do, due to a home page request, switch it back to home.do
    	if (urlString.endsWith("feature.do?itemType=HOMEACTION")){
    		urlString = urlString.replace("feature.do?itemType=HOMEACTION", "home.do");
    	}
    	return urlString;
    }   

    /**
     * Stores request attributes in session
     */
    public static void stowRequestAttributes(HttpServletRequest aRequest) {

        if (aRequest.getSession().getAttribute(STOWED_REQUEST_ATTRIBS) != null) {
            return;
        }

        Enumeration enumeration = aRequest.getAttributeNames();
        Map map = new HashMap();
        while (enumeration.hasMoreElements()) {
            String name = (String) enumeration.nextElement();
            map.put(name, aRequest.getAttribute(name));
        }
        aRequest.getSession().setAttribute(STOWED_REQUEST_ATTRIBS, map);
    }

    /**
     * Returns request attributes from session to request
     */
    public static void reclaimRequestAttributes(HttpServletRequest aRequest) {
        Map map = (Map) aRequest.getSession().getAttribute(STOWED_REQUEST_ATTRIBS);

        if (map == null) {
            return;
        }

        Iterator itr = map.keySet().iterator();
        while (itr.hasNext()) {
            String name = (String) itr.next();

            aRequest.setAttribute(name, map.get(name));
        }

        aRequest.getSession().removeAttribute(STOWED_REQUEST_ATTRIBS);
    }

}

